import grails.util.GrailsWebUtil
import javax.servlet.http.HttpServletResponse
import org.codehaus.groovy.grails.commons.ConfigurationHolder
import org.codehaus.groovy.grails.web.converters.AbstractConverter
import org.codehaus.groovy.grails.web.converters.Converter
import org.codehaus.groovy.grails.web.converters.exceptions.ConverterException

/**
*  opengts  {@link www.opengts.org}
*
* mostly copy from opengts kml output
*
* FIXME add lines and geozone
* FIXME  change to groovy style
*
*/

class KFromOpengts extends AbstractConverter implements Converter {
    static final String STYLE_DEFAULT = "DefaultStyle";
    static final String STYLE_START_MOTION = "StartMotionStyle";
    static final String STYLE_START_MOTION_LAST = "StartMotionLastStyle";
    static final String STYLE_IN_MOTION = "InMotionStyle";
    static final String STYLE_IN_MOTION_LAST = "InMotionLastStyle";
    static final String STYLE_STOP_MOTION = "StopMotionStyle";
    static final String STYLE_STOP_MOTION_LAST = "StopMotionLastStyle";

    static int[] ICON_RED_CAR_CIRCLE = [224, 224]
    static int[] ICON_GREEN_CAR = [192, 0]
    static int[] ICON_GREEN_CAR_CIRCLE = [192, 32]
    static int[] ICON_YELLOW_CAR = [224, 128]
    static int[] ICON_YELLOW_CAR_CIRCLE = [224, 160]
    static int[] ICON_RED_CAR = [224, 192]

    static String ct = 'application/vnd.google-earth.kml+xml kml'

    Eventdata[] object
    String encoding;
    static final String DEFAULT_ENCODING = "utf-8";




    public KFromOpengts() {
        Map config = ConfigurationHolder.getFlatConfig();
        Object enc = config.get("grails.converters.encoding");
        if ((enc != null) && (enc.toString().trim().length() > 0)) {
            this.encoding = enc.toString();
        } else {
            this.encoding = DEFAULT_ENCODING;
        }
    }


    public void setTarget(Object arg0) {
        this.object = arg0;
    }

    public void render(Writer writer) throws ConverterException {
        def eds = this.object;
        this.writeEvents_KML(writer, eds)
    }


    boolean writeEvents_KML(out, evdata) throws IOException
    {
        // This does assume that all events belong to the same "Account"

        /* do we have records to print? */
        if ((evdata == null) || (evdata.length == 0)) {
            return false;
        }

        /* account info */
        def account = evdata[0].device.devicegroup.user;
        if (account == null) {
            return false;
        }

        def accountID = account.id;

        /*
        String tzStr = account.getTimeZone();
        if ((tzStr == null) || tzStr.equals("")) {
            tzStr = DateTime.GMT_TIMEZONE;
        }
        TimeZone tz = DateTime.getTimeZone(tzStr);
        */

        /* header */
        out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        out.write("<kml xmlns=\"http://earth.google.com/kml/2.0\">\n");
        out.write("  <Document>\n");

        /* styles */
        out.write(createStyle_KML(STYLE_DEFAULT, ICON_GREEN_CAR));
        out.write(createStyle_KML(STYLE_START_MOTION, ICON_GREEN_CAR));
        out.write(createStyle_KML(STYLE_START_MOTION_LAST, ICON_GREEN_CAR_CIRCLE));
        out.write(createStyle_KML(STYLE_STOP_MOTION, ICON_RED_CAR));
        out.write(createStyle_KML(STYLE_STOP_MOTION_LAST, ICON_RED_CAR_CIRCLE));
        out.write(createStyle_KML(STYLE_IN_MOTION, ICON_GREEN_CAR));
        out.write(createStyle_KML(STYLE_IN_MOTION_LAST, ICON_GREEN_CAR_CIRCLE));

        /* placemarks */
        if (evdata != null) {
            for (int i = 0; i < evdata.length; i++) {
                boolean isLast = (i == (evdata.length - 1));
                this.writeEvents_KML_Placemark(out, evdata[i], isLast, 4);
            }
        }

        /* trailer */
        out.write("  </Document>\n");
        out.write("</kml>\n");

        /* flush (output may not occur this the PrintWriter is flushed) */
        out.flush();
        return true;

    }

    def writeEvents_KML_Placemark(out, ev, isLast, indent) throws IOException {
        def account = ev.device.devicegroup.user
        //TimeZone tz      = account.getTimeZone(null);
        //Locale locale    = null; // TODO:
        String tab = " " * indent;

        def dt = new Date(ev.timestamp.getTime());
        String datStr = dt.toString();
        int code = ev.statusCode
        String codStr = "normal state" //FIXME

        def lat = ev.latitude
        def lon = ev.longitude

        String deviceID = ev.id
        //double odomKM    = ev.getOdometerKM();
        String address = ev.address
        double heading = ev.heading
        def latStr = "" + lat
        def lonStr = "" + lon
        long altStr = Math.round(ev.altitude);
        def spdStr = ev.speed

        out.write(tab + "<Placemark>\n");
        out.write(tab + "  <name>" + deviceID + "</name>\n");
        out.write(tab + "  <description><![CDATA[");
        out.write("Status  : <strong>" + codStr + "</strong><br>");
        out.write("Date    : <strong>" + datStr + "</strong><br>");
        if ((address != null) && !address.equals("")) {
            out.write("Address : <strong>" + address + "</strong><br>");
        }
        out.write("Speed   : <strong>" + spdStr + "</strong> mph<br>");
        out.write("GPS     : <strong>" + latStr + " " + lonStr + "</strong><br>");
        out.write("Altitude: <strong>" + altStr + "</strong> Meters <br>");

        //if (odomKM > 0.0) {
        //	 out.write(           "Odometer: <strong>" + odomKM  + "</strong> Km");
        //}

        out.write("]]></description>\n");
        String style = STYLE_DEFAULT;
        switch (code) {
            case StatusCodes.STATUS_MOTION_START:
                style = isLast ? STYLE_START_MOTION_LAST : STYLE_START_MOTION;
                break;
            case StatusCodes.STATUS_MOTION_STOP:
                style = isLast ? STYLE_STOP_MOTION_LAST : STYLE_STOP_MOTION;
                break;
            case StatusCodes.STATUS_MOTION_IN_MOTION:
                style = isLast ? STYLE_IN_MOTION_LAST : STYLE_IN_MOTION;
                break;
        }
        out.write(tab + "  <styleUrl>#" + style + "</styleUrl>\n");
        out.write(tab + "  <Point>\n");
        out.write(tab + "    <coordinates>" + lonStr + "," + latStr + ",0</coordinates>\n");
        out.write(tab + "  </Point>\n");
        out.write(tab + "</Placemark>\n");

    }

    def String createStyle_KML(String name, int[] icon)
    {
        StringBuffer st = new StringBuffer();
        st.append("    <Style id=\"" + name + "\">\n");
        st.append("      <BalloonStyle id=\"DefaultBalloonStyle\">\n");
        st.append("        <text><![CDATA[<b>\$[name]</b><br/><br/>\$[description]]]></text>\n");
        st.append("      </BalloonStyle>\n");
        st.append("      <IconStyle id=\"DefaultIconStyle\">\n");
        st.append("        <color>ffffffff</color>\n");
        st.append("        <scale>0.70</scale>\n");
        st.append("        <Icon>\n");
        st.append("          <href>root://icons/palette-4.png</href>\n");
        st.append("          <x>" + icon[0] + "</x>\n");
        st.append("          <y>" + icon[1] + "</y>\n");
        st.append("          <w>32</w>\n");
        st.append("          <h>32</h>\n");
        st.append("        </Icon>\n");
        st.append("      </IconStyle>\n");
        st.append("      <LabelStyle id=\"DefaultLabelStyle\">\n");
        st.append("        <color>ffffffff</color>\n");
        st.append("        <scale>0.70</scale>\n");
        st.append("      </LabelStyle>\n");
        st.append("      <LineStyle id=\"DefaultLineStyle\">\n");
        st.append("        <color>ff0000ff</color>\n");
        st.append("        <width>15</width>\n");
        st.append("      </LineStyle>\n");
        st.append("      <PolyStyle id=\"DefaultPolyStyle\">\n");
        st.append("        <color>7f7faaaa</color>\n");
        st.append("        <colorMode>normal</colorMode>\n");
        st.append("      </PolyStyle>\n");
        st.append("    </Style>\n");
        return st.toString();
    }




    void render(HttpServletResponse response) throws ConverterException {
        response.setContentType(GrailsWebUtil.getContentType(ct, this.encoding));
        try {
            Writer writer = response.getWriter();
            // String encoding = response.getCharacterEncoding();
            render(writer);
        } catch (IOException e) {
            throw new ConverterException(e);
        }

    }
}